﻿#include "IniNode.h"


#pragma warning ( push )
#pragma warning ( disable : 4290 )


namespace ksini
{

IniNode::IniNode(const std::string&  name, const std::string& comment_line, IniNode* pRoot) throw (std::runtime_error)
{
	m_root = pRoot;

	std::string temp;

	temp = name;
	detail::trim_string(temp);

	if(temp.empty() )
	{
		throw std::runtime_error("Empty name");
	}
 
	for(size_t c=0; c<temp.length(); c++)
	{
		if( isdigit(name[c])) continue;
		if( (temp[c] >= 'a') && (temp[c] <='z') )   continue;
		if( (temp[c] >= 'A') && (temp[c] <='Z') )   continue;
		if( temp[c] == '_' )   continue;
		if( temp[c] == '-' )   continue;
		//if( name[c] == '.' )   continue;


		throw std::runtime_error("bad node name");
	}

 
	m_name = temp;

	//=====================

	temp = comment_line;
	detail::trim_string(temp);

	for(size_t c=0; c<temp.length(); c++)
	{
		if( temp[c] == '\n' )
		{
			temp[c] = ' ';
			//throw std::runtime_error("bad comment line");
		}
	}

	detail::trim_string(temp);
	m_comment_line  = temp;




}

std::string  IniNode::makeHierarhyName() const
{
	std::string res;

	if (hasRoot() )
	{
		res = getRoot().makeHierarhyName();
		res += ".";
	}

	
	res += m_name;

	return res;
}


void IniNode::readFromStr(const std::string& str) throw(std::runtime_error)
{
	clearKeyValues();
	clearNodes();

	std::vector<std::string> lines;
	detail::split_lines(lines, str, false);

	if(lines.size() == 0) 
	{
		throw std::runtime_error("source string is empty");
	}

	std::string current;

	std::string key;
	std::string value;
	std::string comment;

	for(size_t c=0; c<lines.size(); c++)
	{
		current = lines[c];

		assert(false);

		if(current.empty() )
		{
			comment = "";
			continue;
		}

		if(detail::is_comment(comment, current))
		{
			continue;
		}


		{
			std::string section_name;

			if(detail::is_section_name(section_name, current) )
			{
				// new node  
				IniNode& new_node = apendChildNode(section_name, comment);
 

				while( c<lines.size() )
				{
					c++;
					current = lines[c];

					if(current.empty() )
					{
						comment = "";
						continue;
					}

					if(detail::is_comment(comment, current))
					{
						continue;
					}

					if( detail::extractKeyValue(key, value, current) )
					{
						IniKeyValue kval(key, value, comment);
						new_node.apendChildKeyValue(kval);
					}


					//break;
				}
			}

		}
		





	}
	//  for



}

void IniNode::apendToStr(std::string& str, int& level) const
{
	

	// before
    str += "\n";
	for(int j=0; j<level; j++)
	{
		str += "\t";
	}
	str += "\n";


	// comment
	if(this->m_comment_line.length() > 0)
	{
		for(int j=0; j<level; j++)
		{
			str += "\t";
		}

		str += "; ";
		str += this->m_comment_line;
		str += "\n";
	}

	// name
	{
		for(int j=0; j<level; j++)
		{
			str += "\t";
		}

		str += "["; 
		str += makeHierarhyName(); // m_name;
		str += "]";
		str += "\n";
	}


	// childs keyvalues
	{
		if( this->hasChildsKeyValues() )
		{
 
			for(size_t c=0; c<m_childrens_key_values.size(); c++)
			{
 
				if( m_childrens_key_values.at(c).get_comment_line().length() > 0 )
				{

					for(int j=0; j<level; j++)
					{
						str += "\t";
					}

					str += "; ";
					str += m_childrens_key_values.at(c).get_comment_line();
					str += "\n";
				}


				for(int j=0; j<level; j++)
				{
					str += "\t";
				}

				str += m_childrens_key_values.at(c).makeKeyValueLine();
				str += "\n";

				for(int j=0; j<level; j++)
				{
					str += "\t";
				}

 
			}

 
		}

	}


	// child nodes
	{
		if( this->hasChildsNodes() )
		{
			level ++;
			   
			for(size_t c=0; c<m_child_nodes.size(); c++)
			{
				// makeHierarhyName();
 
				m_child_nodes.at(c).apendToStr(str, level);
 
				for(int j=0; j<level; j++)
				{
					str += "\t";
				}
 
			}

			level--;
		}
	}


	// after
	for(int j=0; j<level; j++)
	{
		str += "\t";
	}

	str += "\n";
}

void IniNode::apendChildKeyValue(IniKeyValue& kv)    throw(std::runtime_error)
{
	m_childrens_key_values.push_back(kv);
}

void IniNode::apendChildKeyValue(const std::string& key, const std::string& value, 
				const std::string& comment)  throw(std::runtime_error)
{
	 IniKeyValue kv(key, value, comment);

	 m_childrens_key_values.push_back(kv);
}

IniNode& IniNode::apendChildNode(const std::string& node_name, const std::string& node_comment) 
						throw (std::runtime_error)
{
	 IniNode nnew(node_name, node_comment, this);

	 m_child_nodes.push_back(nnew);
	 IniNode& res = m_child_nodes.at( m_child_nodes.size() - 1 );

	 return res;
}

bool IniNode::eraseKey(const std::string& keyName)
{
	if(m_childrens_key_values.empty()) return false;

	for(size_t c=0; c<m_childrens_key_values.size(); c++)
	{
		if( m_childrens_key_values.at(c).get_key() == keyName )
		{
			m_childrens_key_values.erase( m_childrens_key_values.begin() + c );
			return true;
		}
	}

	return false;
}


bool IniNode::eraseNode(const std::string& nodeName)
{
	if(m_child_nodes.empty()) return false;

	for(size_t c=0; c<m_child_nodes.size(); c++)
	{			 
		if( m_child_nodes.at(c).get_node_name() == nodeName )
		{
			m_child_nodes.erase( m_child_nodes.begin() + c );
			return true;
		}
	}


	return false;
}


}


#pragma warning ( pop )


